<template>
	<section class="upload-Media">
		<!-- 上传图片 -->
		<template v-if="props.mode === 'image'">
			<section class="upload-media-wrap">
				<template v-if="state.fileList && state.fileList.length > 0">
					<section
						class="upload-media"
						v-for="(media, mediaIndex) in state.fileList"
						:key="media.key"
						@mouseover.passive="cardMouseOver(mediaIndex)"
						@mouseleave.passive="cardMouseleave(mediaIndex)"
					>
						<section class="media-wrap expandFixed mb10" :style="mediaWrap">
							<el-image preview-teleported style="width: 100%; height: 100%" :src="media?.cropper || media?.path" fit="cover" />
							<section class="image-expand" :style="mediaWrap" v-if="media.active">
								<!-- 裁切 -->
								<section class="expand" :style="iconWeight" v-if="props.cropper && !props.disabled" @click.stop="expandHandler(mediaIndex, 0)">
									<el-icon :size="props.iconSize" color="#fff">
										<Crop />
									</el-icon>
								</section>
								<!-- 预览 -->
								<section class="expand" :style="iconWeight" @click.stop="expandHandler(mediaIndex, 1)">
									<el-icon :size="props.iconSize" color="#fff">
										<View />
									</el-icon>
								</section>
								<!-- 删除 -->
								<section class="expand" :style="iconWeight" v-if="props.isDelete && !props.disabled" @click.stop="expandHandler(mediaIndex, 2)">
									<el-icon :size="props.iconSize" color="#fff">
										<Delete />
									</el-icon>
								</section>
							</section>
							<section style="text-align: center">
								<slot name="label"></slot>
							</section>
						</section>
					</section>
				</template>
				<section class="upload-media" v-if="state.isShowUpload">
					<section class="media-wrap" :style="mediaWrap">
						<el-upload
							:style="mediaWrap"
							class="avatar-media-uploader mb10"
							:show-file-list="false"
							:limit="props.limit"
							:multiple="multiple"
							:disabled="props.disabled"
							:accept="Extended"
							:before-upload="beforeUpload"
							:http-request="uploadStart"
							:on-change="handlerFileChange"
							:autoUpload="props.autoUpload"
						>
							<el-icon class="avatar-uploader-icon" :style="mediaWrap">
								<Plus />
							</el-icon>
							<section class="size-tips" v-if="props.cropperSize">
								<p>尺寸推荐</p>
								<p>{{ `${props.cropperSize}` }}</p>
							</section>
						</el-upload>
						<section style="text-align: center">
							<slot name="label"></slot>
						</section>
					</section>
				</section>
			</section>
		</template>
		<template v-else-if="props.mode === 'video'">
			<section class="upload-media-wrap">
				<template v-if="state.fileList && state.fileList.length > 0">
					<section
						class="upload-media expandFixed"
						:style="mediaWrap"
						v-for="(media, mediaIndex) in state.fileList"
						:key="media.key"
						@mouseover.passive="cardMouseOver(mediaIndex)"
						@mouseleave.passive="cardMouseleave(mediaIndex)"
					>
						<video style="width: 100%; height: 100%; border-radius: 4px" :src="media.path" :controls="props.disabled"></video>
						<section class="image-expand" :style="mediaWrap" v-if="media.active && !props.disabled">
							<!-- 删除 -->
							<section class="expand" :style="iconWeight" v-if="props.isDelete" @click.stop="expandHandler(mediaIndex, 2)">
								<el-icon :size="props.iconSize" color="#fff">
									<Delete />
								</el-icon>
							</section>
						</section>
					</section>
				</template>
				<section class="upload-media" :style="mediaWrap" v-if="state.isShowUpload">
					<el-upload
						:style="mediaWrap"
						class="avatar-media-uploader"
						:show-file-list="false"
						:limit="props.limit"
						:multiple="multiple"
						:disabled="props.disabled"
						:accept="Extended"
						:before-upload="beforeUpload"
						:http-request="uploadStart"
						:on-change="handlerFileChange"
						:autoUpload="props.autoUpload"
					>
						<el-icon class="avatar-uploader-icon" :style="mediaWrap">
							<Plus />
						</el-icon>
					</el-upload>
				</section>
			</section>
		</template>
		<cropperMedia ref="cropperMediaRef" @confirm="cropperConfirm" @cancel="cropperCancel"></cropperMedia>
		<el-image-viewer teleported v-if="state.previewDialog" :url-list="[state.previewUrl]" @close="closePreview" />
	</section>
</template>
<script lang="ts" setup>
import * as tools from '/@/utils/tools';
import imageTools from './imageTools';
import ossClient from '/@/ossUtils';
import { ElLoading } from 'element-plus';
import { computed, reactive, ref, watch, defineAsyncComponent, inject, onUnmounted, nextTick } from 'vue';
import requestAPi from '/@/api';
let timeout = null as any;
console.log(imageTools, 'imageTools');
const cropperMedia = defineAsyncComponent(() => import('./cropperMedia.vue'));
const cropperMediaRef = ref();
const emits = defineEmits(['update:modelValue', 'onChange']);
const props = defineProps({
	//文件列表
	modelValue: {
		type: [<any>Array, String],
		required: true,
	},
	mode: {
		//上传的类型  image/video
		type: String,
		default: 'image',
	},
	//接受上传的文件类型
	accept: {
		type: String,
		default: '',
	},
	//上传的个数 当个数 > 1 时 可以多选
	limit: {
		type: Number,
		default: 1,
	},
	// 是否禁用上传
	disabled: {
		type: Boolean,
		default: () => false,
	},
	width: {
		type: String,
	},
	height: {
		type: String,
	},
	//是否需要裁切 需要请传剪切的 宽高
	cropper: {
		type: Object,
	},
	isDelete: {
		type: Boolean,
		default: () => true,
	},
	iconSize: {
		//拓展图标的大小
		type: Number,
		default: () => 20,
	},
	cropperSize: {
		type: String,
	},
	// 桶目录
	dir: {
		type: String,
		default: () => 'default',
	},
	//图片压缩比例
	gzip: {
		type: [Number, String],
		default: () => '100',
	},
	autoUpload: {
		type: Boolean,
		default: () => true,
	},
});
const state = reactive<any>({
	isShowUpload: true,
	fileList: [], //当前组件内的文件列表
	previewDialog: false,
	previewUrl: '',
});
const multiple = computed(() => {
	return props.limit > 1 ? true : false;
});
const iconWeight = computed(() => {
	return {
		width: `${props.iconSize}px`,
		height: `${props.iconSize}px`,
	};
});
const mediaWrap = computed(() => {
	if (props.mode === 'image') {
		return {
			width: props.width ?? '125px',
			height: props.height ?? '125px',
		};
	} else if (props.mode === 'video') {
		return {
			width: props.width ?? '250px',
			height: props.height ?? '180px',
		};
	}
});
const Extended = computed(() => {
	if (props.accept) return props.accept;
	else {
		switch (props.mode) {
			case 'image':
				return '.png, .jpg, .jpeg';
				break;
			case 'video':
				return '.mp4';
				break;
			case 'audio':
				return 'audio/*';
				break;
		}
	}
});
watch(
	() => props.modelValue,
	() => {
		formatFileList();
	},
	{ immediate: true, deep: true }
);
function handlerFileChange(uploadFile: any) {
	if (props.autoUpload) return;
	beforeUpload(uploadFile.raw);
}
//选择文件事件
function beforeUpload(rawFile: File): Promise<void> {
	return new Promise((resolve, reject) => {
		state.fileList = state.fileList.concat([
			{
				i: state.fileList.length,
				path: props.mode === 'image' ? window.URL.createObjectURL(rawFile) : rawFile,
				rawFile: rawFile,
				active: false,
				key: tools.guid(8),
				progress: 0,
				onProgress: () => {},
			},
		]);
		debounce(() => {
			state.isShowUpload = state.fileList.length >= props.limit ? false : true;
			if (props.mode === 'image' && props.cropper) {
				cropperMediaRef.value?.initComponent({
					cropper: props.cropper,
					fileList: ossClient.uploadImageUrl
						? state.fileList.filter((item: any) => item.path.indexOf(ossClient.uploadImageUrl) === -1)
						: state.fileList,
				});
				reject();
			} else resolve();
		});
		// else if (props.mode === 'image' && !props.cropper) {
		// 	console.log(state.fileList);
		// 	uploadStart();
		// 	// let base64Task = <any>[];
		// 	// state.fileList.forEach((file: any) => {
		// 	// 	base64Task.push(
		// 	// 		new Promise((resolve, reject) => {
		// 	// 			pathToBase64(file.path).then((result: any) => {
		// 	// 				return resolve({
		// 	// 					...file,
		// 	// 					cropper: result,
		// 	// 				});
		// 	// 			});
		// 	// 		})
		// 	// 	);
		// 	// });
		// 	// Promise.all(base64Task).then((base64List: any) => {
		// 	// 	let fileTask = <any>[];
		// 	// 	base64List.forEach((base64: any) => {
		// 	// 		fileTask.push(
		// 	// 			new Promise((resolve, reject) => {
		// 	// 				base64.cropper = base64toFile(base64.cropper);
		// 	// 				return resolve(base64);
		// 	// 			})
		// 	// 		);
		// 	// 	});
		// 	// 	Promise.all(fileTask).then((fileList: any) => {
		// 	// 		state.fileList = fileList;
		// 	// 		uploadStart();
		// 	// 	});
		// 	// });
		// } else if (props.mode === 'video') {
		// 	resolve()
		// }
	});
}
function uploadStart() {
	if (ossClient.uploadImageUrl) {
		//OSS上传
		ossClient
			.uploadMedia(
				['image', 'video'].findIndex((item: string) => item === props.mode),
				state.fileList.map((item: any) => (item?.cropper ? item.cropper : item.rawFile || item.path)),
				'admin_' + props.mode + '/' + props.dir
			)
			.then((result: any) => {
				console.log(result, '上传结果');
				if (props.mode === 'image') {
					function formatGzip(str: string) {
						return str.indexOf('?x-oss-process=image/quality,q_') > -1
							? str.substring(0, str.indexOf('?x-oss-process=image/quality,q_')) + `?x-oss-process=image/quality,q_${props.gzip}`
							: `${str}?x-oss-process=image/quality,q_${props.gzip}`;
					}
					let taskFormat = props.gzip
						? result.map((item: string) => {
								return formatGzip(item);
						  })
						: result;
					emits('update:modelValue', taskFormat);
				} else {
					emits('update:modelValue', result);
				}
			});
	} else {
		const formData = new FormData();
		state.fileList.forEach((item: any) => {
			formData.append('files', item.rawFile);
		});
		formData.append('folder', props.dir);
		requestAPi('/util/file/local/multiple', 'formData', formData)?.then((res) => {
			if (props.mode === 'image') {
				// imageTools.imageCompressionBefore(res.data)
				emits('update:modelValue', res.data);
				emits('onChange');
			} else {
				emits('update:modelValue', res.data);
				emits('onChange');
			}
		});
	}
}

function expandHandler(index: number, type: number) {
	switch (type) {
		case 0:
			//裁切
			cropperMediaRef.value?.initComponent({
				cropper: props.cropper,
				fileList: [state.fileList[index]],
			});
			break;
		case 1:
			//预览
			state.previewUrl = state.fileList[index]?.cropper || state.fileList[index]?.path;
			console.log(state.previewUrl);
			state.previewDialog = true;
			break;
		case 2:
			//删除
			state.fileList.splice(index, 1);
			state.isShowUpload = state.fileList.length >= props.limit ? false : true;
			emits(
				'update:modelValue',
				state.fileList.map((item: any) => item.path)
			);
			break;
	}
}
function closePreview() {
	state.previewDialog = false;
	state.previewUrl = '';
}
function cardMouseleave(index: number) {
	state.fileList[index].active = false;
}
function cardMouseOver(index: number) {
	state.fileList[index].active = true;
}
function cropperCancel() {
	state.fileList = state.fileList.filter((item: any) => item.path.indexOf('https') > -1);
	state.isShowUpload = state.fileList.length >= props.limit ? false : true;
}
function cropperConfirm(result: any) {
	const loadingInstance = ElLoading.service();
	Promise.all(result.map((item: any) => imageTools.base64ToPath(item.cropper))).then((paths: EmptyArrayType) => {
		result.forEach((item: any, index: number) => {
			item.path = paths[index];
		});
		Promise.all(result.map((item: any) => imageTools.base64toFile(item.cropper))).then((files: EmptyArrayType) => {
			state.fileList = result.map((item: any, index: number) => {
				return { ...item, rawFile: files[index], cropper: files[index] };
			});
			console.log(state.fileList, '任务完成');
			if (props.autoUpload) uploadStart();
			else
				emits(
					'update:modelValue',
					state.fileList.map((item: any) => item.path)
				);
			nextTick(() => {
				// Loading should be closed asynchronously
				loadingInstance.close();
			});
		});
	});
}
//把外部数据格式化 变成组件内可用格式
function formatFileList() {
	if (!props.modelValue || props.modelValue?.length === 0) return;
	let filePaths = Array.isArray(props.modelValue) ? props.modelValue : [props.modelValue];
	let idx = 0;
	state.fileList = filePaths.map((item: any, index: number) => {
		let params = { i: idx, path: item, active: false, key: tools.guid(8), progress: 0, onProgress: () => {} };
		idx++;
		return params;
	});
	state.isShowUpload = state.fileList.length >= props.limit ? false : true;
	console.log(state.fileList, '初始化当前文件列表', state.isShowUpload);
}

/**
 * 防抖原理：一定时间内，只有最后一次操作，再过wait毫秒后才执行函数
 *
 * @param {Function} func 要执行的回调函数
 * @param {Number} wait 延时的时间
 * @param {Boolean} immediate 是否立即执行
 * @return null
 */
function debounce(func: Function, wait = 500, immediate = false) {
	// 清除定时器
	if (timeout !== null) clearTimeout(timeout);
	// 立即执行，此类情况一般用不到
	if (immediate) {
		var callNow = !timeout;
		timeout = setTimeout(function () {
			timeout = null;
		}, wait);
		if (callNow) typeof func === 'function' && func();
	} else {
		// 设置定时器，当最后一次操作后，timeout不会再被清除，所以在延时wait毫秒后执行func回调方法
		timeout = setTimeout(function () {
			typeof func === 'function' && func();
		}, wait);
	}
}
onUnmounted(() => {
	state.isShowUpload = false;
	state.fileList = [];
	state.previewDialog = false;
	state.previewUrl = '';
});
</script>
<style lang="scss" scoped>
::v-deep .el-form-item--large {
	line-height: unset !important;
}

::v-deep .el-form-item__content {
	line-height: unset !important;
}

.upload-Media {
	width: 100%;
	display: flex;
	flex-wrap: wrap;
	flex-direction: column;
	align-items: center;

	.upload-media-wrap {
		width: 100%;
		display: flex;
		flex-wrap: wrap;
		align-items: flex-start;
		gap: 12px;

		.expandFixed {
			position: relative;

			.media-wrap {
				display: flex;
				flex-direction: column;
			}
		}

		.upload-media {
			display: flex;
			flex-direction: column;
			cursor: pointer;
			border-radius: 6px;

			video {
				width: 100%;
				height: 100%;
				object-fit: cover;
			}

			.avatar-media-uploader {
				border: 1px dashed var(--el-border-color);
				flex: 1 1 0%;
				display: flex;
				align-items: center;
				justify-content: center;
				cursor: pointer;
				position: relative;
				overflow: hidden;
				transition: var(--el-transition-duration-fast);
				display: flex;
				align-items: center;
				justify-content: center;

				&:hover {
					width: 100%;
					height: 100%;
					border-color: var(--el-color-primary);
				}

				.avatar-uploader-icon {
					width: 100%;
					height: 100%;
					font-size: 28px;
					color: #8c939d;
					text-align: center;
				}

				.size-tips {
					width: 100%;
					height: 100%;
					// background: rgba(0, 0, 0, 0.2);
					color: #f83e46;
					font-size: 14px;
					position: absolute;
					display: flex;
					flex-direction: column;
					align-items: center;
					justify-content: space-around;
					bottom: 0;
					padding: 4px 0;
					line-height: unset !important;

					p {
						text-align: center !important;
						font-weight: 550 !important;
						line-height: unset !important;
					}
				}
			}
		}
	}
}

.image-expand {
	position: absolute;
	top: 0;
	left: 0;
	right: 0;
	bottom: 0;
	margin: 0 auto;
	z-index: 100;
	background: rgba(0, 0, 0, 0.6);
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 15px;

	.expand {
		// width: 25px;
		// height: 25px;
		display: flex;
		align-items: center;
		justify-content: center;
	}
}
</style>
